// 1)常见的类型推导的方式
let name = "jiangwen"; //根据赋值来进行推导let age = 30;

//2)根据返回值来进行类型推导，自动推导返回值类型
//function sum(a: string,b: string){return a + b};

//3)会根据上下文来推导赋予值的类型 根据位置推导
type ISum = (x: string, y: string) => string;
let sum: ISum = (a, b) => {
  // a, b，返回值会根据ISum推导类型
  return a + b;
};

//3)会根据上下文来推导赋予值的类型(根据位置来进行推导的)
type ICallback = (a: string, b: number, c: boolean) => void;
// type申明 函数返回void 表示不关心返回的具体类型
function fn(callback: ICallback) {}
// 参数只可以少，不可以多
fn((x, y, z) => {
  return {};
});

// 函数中的类型 1）函数的声明方式 2） 函数的参数  3） 函数的返回值

// function关键字来声明的函数可以提升到当前作用域顶部

// 对于ts来说有区别： 函数关键字声明的函数 不能标注函数类型

// 通过表达式来声明的函数： 必须赋予的值要满足定义的类型 (要求有一个兼容性在里面)

// function sum(a:string,b:string):string{
//     return a+b
// }

// 1)函数类型的定义  (a: any, b: any) => any  ｜   (a: any, b: any) : any
// type ISum = {(a: any, b: any) : any}
// type ISum =  (a: any, b: any) => any
// const sum:ISum  = function(a:string,b:string){
//     return a+b
// }
// 如果标明函数的类型，在使用函数的时候以标明的为准

// 2)参数 可选参数 ? 可选参数 意味着可以不传. ?和 string | undefiend相同 必须得传。 可选参数只能在参数列表中的后面
// 表示默认值 =
// type ISum =  (a: string, b?: string) => string
// sum1和sum2，是相同。sum2会自己推导
// const sum1 = function(a:string,b:string = 'abc'){
//     return a+b
// }
// const sum2 = function(a,b){
//     return a+b
// }s
// // 这里如果是兼容处理 采用的是自己标识的  不是你复制的类型
// sum('1')

//函数的剩余参数(剩余运算符 类型是数组)....................................................................
let total = (...rest: number[]): number => {
  return rest.reduce((memo, current) => ((memo += current), memo));
};

// 3) 参数this问题....................................................................
// 尽量不采用this 来作为函数的上下文， this的缺陷就是类型推导问题
// 如果想限制this类型 那么需要手动指定this类型
// 我想根据值来获得类型  typeof， 配合type来声明新的类型
const person = { name: "jw", age: 30, address: "昌平霍营" };
//  typeof提取person对象的数据类型，为IPerson, type类型会提升到顶部
type IPerson = typeof person; // ==> {name : string , age: number , address: string}
// keyof 后面要放数类型 可以获取对象型的数据类例如IPerson中所有key 作为联合类型
type IKeys = keyof IPerson; // ==> 'name' | 'age' | 'address'
function getValue(this: IPerson, key: IKeys) {
  // this不是行参 是标明this的类型
  return this[key];
}
// 可以将子类型赋予给父类型
getValue.call(person, "age");

// 重载-----根据不同参数 输入类型，采取不同操作....................................................................
// 函数中有arguments 但是我们不建议使用
// function sum(...args:number[]):number{ // （函数式编程 入参和返回值 组合式api） 函数 （不考虑使用this 和 arguments）
//     return args.reduce((memo,current)=>(memo += current,memo),0)
// }

// 参数的类型直接参数后面:标识  函数的返回值在 {}前面来标识
// const sum: (...args:any[])=> any = (...args:any[]) :any=> {
//     return
// }

// ts 中函数有一个概念 叫重载(类型的重载)， 对于强类型语言可以一个函数写多遍（参数不同） js实现重载考的是arguments

// 入参是一个字符串 或者是数字  -》 【‘字符串’】  【‘数字’】

// string[] | number[]    (number|string)[]

//重载(一般是有限操作)ts中的重载是伪重载(类型的重载 而不是逻辑的重载)
function toArray(value: string): string[];
function toArray(value: number): number[];
// 上面的声明仅仅是类型上的重载，在不同的参数情况下，让类型范围缩小，对js逻辑没影响
function toArray(value: number | string): string[] | number[] {
  //123 [1,2,3]，'123'['1','2',"3']
  if (typeof value === "string") {
    return value.split("");
  } else {
    return value.toString().split("").map(Number);
  }
}
let arr1 = toArray("123");
let arr2 = toArray(123);

export {};
